package com.fzq.config.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fzq.util.ResponseResult;
import org.springframework.http.MediaType;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.nio.charset.StandardCharsets;

/**
 * 鉴权处理器
 *
 * 这个 SimpleAccessDeniedHandler 类是 Spring Security 中处理权限不足（访问被拒绝）的异常处理器。当用户已通过认证（登录成功），但尝试访问其 没有权限的资源（例如普通用户访问管理员接口）时，Spring Security 会抛出 AccessDeniedException，此时该类的 handle 方法会被触发，返回自定义的 JSON 响应。以下是详细解析：
 *
 * 核心作用
 * 替代默认的 HTTP 403 页面
 * Spring Security 默认会返回 HTTP 403 状态码和一个空白页（或错误页）。通过自定义 AccessDeniedHandler，可以统一返回结构化的 JSON 数据（如状态码、错误信息），方便前端处理。
 * 标准化错误响应
 * 将权限不足的异常信息封装为业务约定的格式（例如 ResponseResult 对象），保持接口响应一致性。
 */
@Component
public class SimpleAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest request,
                       HttpServletResponse response,
                       AccessDeniedException e) throws IOException, ServletException {

        // 1. 创建自定义错误响应对象
        ResponseResult<Void> responseResult = new ResponseResult<>(4003, "无此权限，请联系管理员");

        // 2. 设置 HTTP 响应状态码（此处设置为 200，但业务状态码是 4003）
        response.setStatus(HttpServletResponse.SC_OK);  // HTTP 200

        // 3. 设置响应编码和内容类型
        response.setCharacterEncoding(StandardCharsets.UTF_8.toString());  // UTF-8 编码
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);         // JSON 格式

        // 4. 将响应对象序列化为 JSON 字符串
        ObjectMapper objectMapper = new ObjectMapper();
        String resBody = objectMapper.writeValueAsString(responseResult);

        // 5. 将 JSON 写入响应流
        PrintWriter printWriter = response.getWriter();
        printWriter.print(resBody);
        printWriter.flush();
        printWriter.close();
    }
}
